package com.btech.dftp.dataimport.dao;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import org.apache.commons.lang3.StringUtils;
import org.quincy.rock.core.exception.DataNotFoundException;
import org.quincy.rock.core.function.EachConsumer;
import org.quincy.rock.core.util.MapUtil;
import org.quincy.rock.core.util.StringUtil;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * <b>数据字典抽象Dao。</b>
 * <p><b>详细说明：</b></p>
 * <!-- 在此添加详细说明 -->
 * 无。
 * <p><b>修改列表：</b></p>
 * <table width="100%" cellSpacing=1 cellPadding=3 border=1>
 * <tr bgcolor="#CCCCFF"><td>序号</td><td>作者</td><td>修改日期</td><td>修改内容</td></tr>
 * <!-- 在此添加修改列表，参考第一行内容 -->
 * <tr><td>1</td><td>wks</td><td>2022年4月21日 上午10:46:24</td><td>建立类型</td></tr>
 * 
 * </table>
 * @version 1.0
 * @author wks
 * @since 1.0
 */
@Transactional(readOnly = true)
public abstract class DictDao extends BaseDao {
	/**
	 * 表名。
	 */
	private String tableName;

	/**
	 * 别名id映射表。
	 */
	private Map<String, Long> aliasMapping;
	private Map<Long, Set<String>> idMapping;

	/**
	 * <b>构造方法。</b>
	 * <p><b>详细说明：</b></p>
	 * <!-- 在此添加详细说明 -->
	 * 无。
	 * @param tableName 表名
	 */
	public DictDao(String tableName) {
		this.tableName = tableName;
	}

	private void addToMapping(Long id, String name) {
		Set<String> nameSet = idMapping.get(id);
		if (nameSet == null) {
			nameSet = new TreeSet<String>();
			idMapping.put(id, nameSet);
		}
		nameSet.add(name);
		aliasMapping.put(name, id);
	}

	private void addToMapping(Long id, Set<String> alias) {
		for (String name : alias) {
			aliasMapping.put(name, id);
		}
		idMapping.put(id, alias);
	}

	private void initMapping() {
		if (aliasMapping == null || idMapping == null) {
			aliasMapping = new HashMap<String, Long>();
			idMapping = new HashMap<Long, Set<String>>();
			for (Map<String, Object> data : this.findAllDict()) {
				final Long id = MapUtil.getLong(data, "f_id");
				addToMapping(id, MapUtil.getString(data, "f_name"));
				String alias = MapUtil.getString(data, "f_alias");
				StringUtil.split(alias, StringUtil.CHAR_COMMA, new EachConsumer<CharSequence>() {

					public void each(int index, CharSequence t) {
						if (!StringUtil.isBlank(t)) {
							addToMapping(id, t.toString());
						}
					}
				});
			}
		}
	}

	/**
	 * <b>查询所有的数据。</b>
	 * <p><b>详细说明：</b></p>
	 * <!-- 在此添加详细说明 -->
	 * 无。
	 * @return 数据列表
	 */
	public List<Map<String, Object>> findAllDict() {
		String sql = daoSupport.getNamedSql("findAllDict", tableName);
		List<Map<String, Object>> list = daoSupport.queryList(sql);
		return list;
	}

	/**
	 * <b>根据名称查找id。</b>
	 * <p><b>详细说明：</b></p>
	 * <!-- 在此添加详细说明 -->
	 * 无。
	 * @param name 名称
	 * @return id值
	 */
	public Long findId(String name) {
		this.initMapping();
		return aliasMapping.get(name);
	}

	/**
	 * <b>根据名称查找id。</b>
	 * <p><b>详细说明：</b></p>
	 * <!-- 在此添加详细说明 -->
	 * 根据名称而不是别名查找id，如果没有找到则新建。
	 * 
	 * @param name 名称,不能为null
	 * @param alias 要保存的别名,允许为null
	 * @return id值
	 */
	@Transactional(propagation = Propagation.REQUIRED)
	public long getId(String name, String saveAlias) {
		this.initMapping();
		if (name.equals(saveAlias))
			saveAlias = null;
		Long id = this.findId(name);
		if (id != null) {
			//找到了
			if (saveAlias != null && !aliasMapping.containsKey(saveAlias)) {
				//有新别名,更新别名
				this.addToMapping(id, saveAlias);
				this.updateDict(id, name, idMapping.get(id));
			}
		} else {
			//没找到，插入
			Set<String> set = new TreeSet<String>();
			set.add(name);
			if (saveAlias != null) {
				set.add(saveAlias);
			}
			id = this.insertDict(name, set);
			this.addToMapping(id, set);
		}
		//
		return id;
	}

	/**
	 * <b>插入一行字典数据。</b>
	 * <p><b>详细说明：</b></p>
	 * <!-- 在此添加详细说明 -->
	 * 无。
	 * @param name 名称
	 * @param alias 别名集合
	 * @return 主键id
	 */	
	private long insertDict(String name, Set<String> alias) {
		String sql = daoSupport.getNamedSql("insertDict", tableName);
		Long id = idGenerator.generate(tableName);
		String aliases = StringUtils.join(alias.iterator(), StringUtil.CHAR_COMMA);
		daoSupport.execute(sql, id, name, aliases);
		return id;
	}

	/**
	 * <b>更新一行字典数据。</b>
	 * <p><b>详细说明：</b></p>
	 * <!-- 在此添加详细说明 -->
	 * 无。
	 * @param id 要更新的数据的主键id
	 * @param name 名称
	 * @param alias 别名集合
	 * @return 主键id
	 */	
	private long updateDict(long id, String name, Set<String> alias) {
		String sql = daoSupport.getNamedSql("updateDict", tableName);
		String aliases = StringUtils.join(alias.iterator(), StringUtil.CHAR_COMMA);
		int i = daoSupport.execute(sql, name, aliases, id);
		if (i == 0)
			throw new DataNotFoundException("未发现要更新的id " + id + " from table " + tableName);
		//
		return id;
	}
}
